package ygo

import ( "fmt"
	 "dumpwave"
)
func pc(
	//pc_command         chan int32,
	instruction_address  chan uint32,
	decodePC             chan DEPC,
	aluPc                chan uint32,
	pcCop0               chan uint32,
	cop0Pc               chan uint32) {

//     var(
// 		vPC,
// 		vCoreInstAddr,
// 		vDecodeInstAddr,
// 		vMemInstAddr int32
// 	)
	var vPC, offset uint32

	fmt.Println("[PC ] Starting Program Counter")
	vPC = 0
	fmt.Println("[PC ] Starting PC=", vPC)
	instruction_address <- vPC
//	vPC ++
//	instruction_address <- vPC
//	vPC ++
//	instruction_address <- vPC

	for {
		depc :=<- decodePC
		switch depc.PC_COMMAND {
				case PC_NEXT:
					fmt.Printf("[PC] DEPC <-- DECODE (cmd: PC_NEXT, immediate: 0x%x, offset: 0x%x)\n",depc.PC_IMMEDIATE,depc.PC_OFFSET)

					vPC += INSTRUCTION_SIZE

				case PC_JUMP_REG:
					fmt.Printf("[PC] DEPC <-- DECODE (cmd: PC_JUMP_REG, immediate: 0x%x, offset: 0x%x)\n",depc.PC_IMMEDIATE,depc.PC_OFFSET)

					vPC =<- cop0Pc
					fmt.Printf("[PC] vPC <-- COP0 (%d)\n",vPC)

				case PC_LINK_AND_JUMP_REG:
					fmt.Printf("[PC] DEPC <-- DECODE (cmd: PC_LINK_AND_JUMP_REG, immediate: 0x%x, offset: 0x%x)\n",depc.PC_IMMEDIATE,depc.PC_OFFSET)

					fmt.Printf("[PC] vPC --> COP0 (%d)\n",vPC)
					pcCop0 <- vPC

					vPC =<- cop0Pc
					fmt.Printf("[PC] vPC <-- COP0 (%d)\n",vPC)

				case PC_BRANCH:
					fmt.Printf("[PC] DEPC <-- DECODE (cmd: PC_BRANCH, immediate: 0x%x, offset: 0x%x)\n",depc.PC_IMMEDIATE,depc.PC_OFFSET)

					var_offset := depc.PC_OFFSET

					var_branch :=<- aluPc
					fmt.Printf("[PC] branch <-- ALU (0x%x)\n",var_branch)

					if var_branch==1 {
						if (var_offset & 0x8000)>>15==0 { //se var_offset.15 == 0
							offset = 0x00000000
						} else {
							offset = 0xFFFF0000
						}
						offset = offset | uint32(var_offset & 0xFFFF)
						//PC POINTS TO PC+OFFSET
						//var_pc := var_pc - INSTRUCTION_SIZE + var_offset;
						//offset is relative to branch delay slot instruction not jump it self
						vPC = vPC - INSTRUCTION_SIZE + offset
					} else {
						//PC POINTS TO NEXT INSTRUCTION
						vPC = vPC + INSTRUCTION_SIZE
					}

				case PC_DELAYED_BRANCH:
					fmt.Printf("[PC] DEPC <-- DECODE (cmd: PC_DELAYED_BRANCH, immediate: 0x%x, offset: 0x%x)\n",depc.PC_IMMEDIATE,depc.PC_OFFSET)

					var_offset := depc.PC_OFFSET

					var_branch :=<- aluPc
					fmt.Printf("[PC] branch <-- ALU (0x%x)\n",var_branch)

					if var_branch==1 {
						if (var_offset & 0x8000)>>15==0 { //se var_offset.15 == 0
							offset = 0x00000000
						} else {
							offset = 0xFFFF0000
						}
						offset = offset | uint32(var_offset & 0xFFFF)
						//PC POINTS TO PC+OFFSET
						//var_pc := var_pc - INSTRUCTION_SIZE - INSTRUCTION_SIZE + var_offset;
						//offset is relative to branch delay slot instruction not jump it self
						vPC = vPC - INSTRUCTION_SIZE - INSTRUCTION_SIZE + offset
					} else {
						//PC POINTS TO NEXT INSTRUCTION
						vPC = vPC + INSTRUCTION_SIZE
					}

				case PC_LINK_AND_BRANCH:
					fmt.Printf("[PC] DEPC <-- DECODE (cmd: PC_LINK_AND_BRANCH, immediate: 0x%x, offset: 0x%x)\n",depc.PC_IMMEDIATE,depc.PC_OFFSET)

					var_offset := depc.PC_OFFSET

					var_branch :=<- aluPc
					fmt.Printf("[PC] branch <-- ALU (0x%x)\n",var_branch)

					if var_branch==1 {
						if (var_offset & 0x8000)>>15==0 { //se var_offset.15 == 0
							offset = 0x00000000
						} else {
							offset = 0xFFFF0000
						}
						offset = offset | uint32(var_offset & 0xFFFF)
						//PC POINTS TO PC+OFFSET
						//var_pc := var_pc - INSTRUCTION_SIZE + var_offset;
						//offset is relative to branch delay slot instruction not jump it self
						vPC = vPC - INSTRUCTION_SIZE + offset
					} else {
						//PC POINTS TO NEXT INSTRUCTION
						vPC = vPC + INSTRUCTION_SIZE
					}

				case PC_LINK_AND_NEXT:
					fmt.Printf("[PC] DEPC <-- DECODE (cmd: PC_LINK_AND_NEXT, immediate: 0x%x, offset: 0x%x)\n",depc.PC_IMMEDIATE,depc.PC_OFFSET)
					vPC =<- aluPc
					fmt.Printf("[PC] vPC <-- ALU (%d)\n",vPC)
					vPC += INSTRUCTION_SIZE

				case PC_IMMEDIATE_JUMP:
					fmt.Printf("[PC] DEPC <-- DECODE (cmd: PC_IMMEDIATE_JUMP, immediate: 0x%x, offset: 0x%x)\n",depc.PC_IMMEDIATE,depc.PC_OFFSET)
					vPC = (vPC &  0xF0000000) | depc.PC_IMMEDIATE<<2

				case PC_LINK_AND_IMMEDIATE_JUMP:
					fmt.Printf("[PC] DEPC <-- DECODE (cmd: PC_LINK_AND_IMMEDIATE_JUMP, immediate: 0x%x, offset: 0x%x)\n",depc.PC_IMMEDIATE,depc.PC_OFFSET)
					//var_offset := depc.PC_OFFSET
		}

		fmt.Printf("[PC] vPC --> YAM (%d)\n", vPC)
		dumpwave.Wave(1,"req_ack_INST")
		dumpwave.Wave(int(vPC),"cha_INST")
		instruction_address <- vPC
		dumpwave.Wave(0,"req_ack_INST")
		
		//pcCop0 <- vPC
// 		vCoreInstAddr = vDecodeInstAddr
// 		vDecodeInstAddr = vMemInstAddr
// 		vMemInstAddr = vPC
	}
}
